/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package pagoda.engine;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.UUID;
import javax.script.ScriptEngine;
import org.w3c.dom.Node;
import pagoda.engine.actions.SequenceAction;
import pagoda.util.StringUtil;
import pagoda.util.exceptions.PagodaException;
import pagoda.util.scripting.Expression;
import pagoda.util.scripting.ExpressionUtil;
import pagoda.util.xml.BasicNodeWalker;
import pagoda.util.xml.NodeVisitor;
import pagoda.util.xml.NodeWalker;
import pagoda.util.xml.XmlUtil;

/**
 *
 * @author Kevin Krohe
 */
public abstract class BaseTestEngineParser {

    private TestEngineParseContext _context
            = new TestEngineParseContext();

    private NodeWalker<TestEngineParseContext> _walker
            = new BasicNodeWalker<TestEngineParseContext>(_context);

    public BaseTestEngineParser()
    {
        Method[] methods = getClass().getMethods();
        final Object target = this;
        
        for(final Method m : methods)
        {
            Annotation a = m.getAnnotation(ParseMethod.class);
            if(a != null)
            {
                ParseMethod parser = (ParseMethod)a;
                String tagname = parser.name();
                _walker.register(tagname, new NodeVisitor<TestEngineParseContext>()
                {

                    public void visitNode(Node xmlnode, TestEngineParseContext context) {
                        TestActionContainer container = context.CurrentContainer;
                        try {
                            TestAction action = (TestAction) m.invoke(
                                    target,
                                    xmlnode,
                                    context
                                    );

                            boolean enabled = Boolean.parseBoolean(
                                    XmlUtil.getAttrValue(
                                        xmlnode,
                                        "enable",
                                        "true"
                                        )
                                    );

                            String name = XmlUtil.getAttrValue(
                                    xmlnode,
                                    "name",
                                    action.getClass().getName()
                                    );

                            action.setId(UUID.randomUUID())
                                    .setName(name)
                                    .setEnabled(enabled)
                                    .setTestEngine(context.CurrentEngine);

                            container.addSubAction(action);

                            String cond = XmlUtil.getAttrValue(xmlnode, "if");
                            if(!StringUtil.IsNullOrEmpty(cond))
                            {
                                Expression<Boolean> condition =
                                        action.buildExpression(
                                        cond
                                        );
                                action.setCondition(condition);
                            }
                            
                        } catch (Throwable ex) {
                            throw new PagodaException(ex, "Failed to construct action for node '%s'", xmlnode.getLocalName());
                        }
                    }
                    
                });
            }
        }
    }

    public TestAction parseChildren(Node xmlnode, TestActionContainer container)
    {
        TestActionContainer c = _context.CurrentContainer;
        _context.CurrentContainer = container;
        container.setTestEngine(_context.CurrentEngine);
        _walker.walk(xmlnode);
        _context.CurrentContainer = c;
        return container;
    }

    public TestAction parse(
            String xml,
            TestEngine engine,
            TestActionContainer container
            )
    {
        _context.CurrentContainer = container;
        _context.CurrentEngine = engine;
        container.setTestEngine(engine);
        _walker.walk(xml, null);
        return container;
    }

    public TestAction parse(
            File file,
            TestEngine engine,
            TestActionContainer container
            )
    {
        _context.CurrentContainer = container;
        _context.CurrentEngine = engine;
        container.setTestEngine(engine);
        _walker.walk(file);
        return container;
    }

}

